﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace vbReturn.classes
{
   /// <summary>
/// Determines how empty lines are interpreted when reading CSV files.
/// These values do not affect empty lines that occur within quoted fields
/// or empty lines that appear at the end of the input file.
/// </summary>
public enum EmptyLineBehavior
{
    /// <summary>
    /// Empty lines are interpreted as a line with zero columns.
    /// </summary>
    NoColumns,
    /// <summary>
    /// Empty lines are interpreted as a line with a single empty column.
    /// </summary>
    EmptyColumn,
    /// <summary>
    /// Empty lines are skipped over as though they did not exist.
    /// </summary>
    Ignore,
    /// <summary>
    /// An empty line is interpreted as the end of the input file.
    /// </summary>
    EndOfFile,
}

/// <summary>
/// Common base class for CSV reader and writer classes.
/// </summary>
public abstract class CsvFileCommon
{
    /// <summary>
    /// These are special characters in CSV files. If a column contains any
    /// of these characters, the entire column is wrapped in double quotes.
    /// </summary>
    protected char[] SpecialChars = new char[] { ',', '"', '\r', '\n' };

    // Indexes into SpecialChars for characters with specific meaning
    private const int DelimiterIndex = 0;
    private const int QuoteIndex = 1;

    /// <summary>
    /// Gets/sets the character used for column delimiters.
    /// </summary>
    public char Delimiter
    {
        get { return SpecialChars[DelimiterIndex]; }
        set { SpecialChars[DelimiterIndex] = value; }
    }

    /// <summary>
    /// Gets/sets the character used for column quotes.
    /// </summary>
    public char Quote
    {
        get { return SpecialChars[QuoteIndex]; }
        set { SpecialChars[QuoteIndex] = value; }
    }
}


/// <summary>
/// Class for writing to comma-separated-value (CSV) files.
/// </summary>
public class CsvFileWriter : CsvFileCommon, IDisposable
{
    // Private members
    private StreamWriter Writer;
    private string OneQuote = null;
    private string TwoQuotes = null;
    private string QuotedFormat = null;

    /// <summary>
    /// Initializes a new instance of the CsvFileWriter class for the
    /// specified stream.
    /// </summary>
    /// <param name="stream">The stream to write to</param>
    public CsvFileWriter(Stream stream)
    {
        Writer = new StreamWriter(stream);
    }

    /// <summary>
    /// Initializes a new instance of the CsvFileWriter class for the
    /// specified file path.
    /// </summary>
    /// <param name="path">The name of the CSV file to write to</param>
    public CsvFileWriter(string path)
    {
        Writer = new StreamWriter(path);
    }

    /// <summary>
    /// Writes a row of columns to the current CSV file.
    /// </summary>
    /// <param name="columns">The list of columns to write</param>
    public void WriteRow(List<string> columns)
    {
        // Verify required argument
        if (columns == null)
            throw new ArgumentNullException("columns");

        // Ensure we're using current quote character
        if (OneQuote == null || OneQuote[0] != Quote)
        {
            OneQuote = String.Format("{0}", Quote);
            TwoQuotes = String.Format("{0}{0}", Quote);
            QuotedFormat = String.Format("{0}{{0}}{0}", Quote);
        }

        // Write each column
        for (int i = 0; i < columns.Count; i++)
        {
            // Add delimiter if this isn't the first column
            if (i > 0)
                Writer.Write(Delimiter);
            // Write this column
            if (columns[i].IndexOfAny(SpecialChars) == -1)
                Writer.Write(columns[i]);
            else
                Writer.Write(QuotedFormat, columns[i].Replace(OneQuote, TwoQuotes));
        }
        Writer.WriteLine();
    }

    // Propagate Dispose to StreamWriter
    public void Dispose()
    {
        Writer.Dispose();
    }
}
}
